﻿using Inaction;
using Inaction.Core;
using Inaction.Mapping;
using Inaction.Util;
using System;
using System.Linq.Expressions;

namespace Inaction
{
    [Serializable]
    public abstract class Model<T> : Core.ModelBase where T : Model<T>, new()
    {
        #region override
        static Mapping.ClassInfo classInfo;

        public static Mapping.ClassInfo ClassInfo
        {
            get
            {
                if (classInfo == null)
                {
                    classInfo = Mapping.ClassInfo.LoadInfo(typeof(T));
                }
                return classInfo;
            }
        }

        Guid? primaryKey;
        public override Guid? PrimaryKey
        {
            get
            {
                if (primaryKey == null)
                {
                    primaryKey = (Guid)ClassInfo.PrimaryKey.GetFieldValue((T)this);
                }
                return primaryKey;
            }
        }

        internal protected override void Init(System.Data.IDataReader reader)
        {
            for (int i = 0; i < reader.FieldCount; i++)
            {
                var value = reader.GetValue(i);
                if (value != DBNull.Value)
                {
                    var property = ClassInfo.MappedProperties[reader.GetName(i)];
                    value = TypeConvert.ConvertToSystemValue(property.UnderlyingType, value);
                    property.SetFieldValue((T)this, value);
                }
            }
        }
        #endregion

        #region 方法

        #region RegisteProperty
        protected static Property<P> RegisteProperty<P>(Expression<Func<T, P>> propertyExpression, P defaultValue = default(P))
        {
            return new Property<P>(ClassInfo, Reflect<T>.GetProperty(propertyExpression), defaultValue);
        }

        protected static Property<P> RegisteProperty<P>(Expression<Func<T, P>> propertyExpression, Func<P> func)
        {
            return new Property<P>(ClassInfo, Reflect<T>.GetProperty(propertyExpression), func);
        }

        protected static Property<P> RegisteProperty<P>(Type entityType, string propertyName, P defaultValue = default(P))
        {
            return   new Property<P>(classInfo, entityType.GetProperty(propertyName), defaultValue);
        }

        #endregion

        #region New
        public static T New()
        {
            var t = new T();
            t.SetDefaultValue();
            return t;
        }
        #endregion

        public void SetDefaultValue()
        {
            var classInfo = ClassInfo.LoadInfo(typeof(T));
            var primary = classInfo.PrimaryKey;
            if (primary != null)
            {
                var val = Sequence.NewId;
                primary.SetFieldValue((T)this, val);
            }
            if (ClassInfo.CreaterProperty != null)
            {
                ClassInfo.CreaterProperty.SetFieldValue((T)this, Inaction.Security.Principal.Instance.Identity.UserNumber);
            }
            if (ClassInfo.CreateTimeProperty != null)
            {
                ClassInfo.CreateTimeProperty.SetFieldValue((T)this, DateTime.Now);
            }
            if (ClassInfo.UpdaterProperty != null)
            {
                ClassInfo.UpdaterProperty.SetFieldValue((T)this, Inaction.Security.Principal.Instance.Identity.UserNumber);
            }
            if (ClassInfo.UpdateTimeProperty != null)
            {
                ClassInfo.UpdateTimeProperty.SetFieldValue((T)this, DateTime.Now);
            }
            foreach (var p in classInfo.DefaultValueProperties)
            {
                p.SetFieldValue((T)this, p.DefaultValue);
            }
        }

        public override bool IsDirty { get { return true; } }

        public override bool IsSelfDirty { get { return true; } }
        public override bool IsPropertyDirty(IProperty property)
        {
            return true;
        }
        #endregion
    }
}
